#include <stdio.h>
#include <string.h>

/*
 * This is probably one of the silliest programs I've made.
 * I wanted to get a good grasp of C function pointers.
 * I started by making an add function.  Then I made a pointer
 * to that add function, then I made an add3 function, which
 * has as one of it's parameters a pointer to add ().
 *
 * Then I made an add4 function, whose parameters include
 * a pointer to add3 () and a pointer to add ().
 *
 * It really starts getting complicated at that point.
 * This is when I should start introducing typedefs
 */

int
add (int a, int b)
{
  return a + b;
}

/* a function that takes a function pointer,
   and 3 values */
int
add3 (int (* pAdd)(int, int), int a, int b, int c)
{
  return (pAdd) (a, b) + c;
}

int
add4 (int (* pAdd3) (int (* pAdd) (int, int), int, int, int),
      int (* pAdd) (int, int),
      int a, int b, int c, int d)
{
  return (pAdd3) (pAdd, a, b, c) + d;
}

int
add5 (
      int (* pAdd4) (int (* pAdd3) ( int (* pAdd) (int, int), int, int, int ),
                     int (*pAdd) (int, int),
                     int, int, int, int),
      int (* pAdd3) ( int (* pAdd) (int, int), int, int, int ),
      int (* pAdd) (int, int),
       int a, int b, int c, int d, int e
      )  
{
  return (pAdd4) (pAdd3, pAdd, a, b, c, d) + e;
}

int
main ()
{
  int (* pAdd)(int, int);
  pAdd = &add;
  int sum = (pAdd) (5, 6);
  printf ("sum is %d\n", sum);

  /* pAdd is a function pointer */
  int sum3 = add3 (pAdd, 1, 2, 3);
  printf ("sum3 is %d\n", sum3);

  int (* pAdd3) (int (* pAdd) (int, int), int a, int b, int c);
  pAdd3 = &add3;
  sum3 = (pAdd3) (pAdd, 1, 2, 3);
  printf ("sum3 is still %d\n", sum3);

  int sum4 = add4 (pAdd3, pAdd, 1, 2, 3, 4);
  printf ("sum4 is %d\n", sum4);

  int (*pAdd4) ( int (* pAdd3) (int (* pAdd) (int, int), int, int, int),
                 int (* pAdd) (int, int),
                 int, int, int, int);
  pAdd4 = &add4;
  sum4 = (pAdd4) (pAdd3, pAdd, 1, 2, 3, 4);
  printf ("sum4 is still %d\n", sum4);

  int (*pAdd5) (int (* pAdd4) ( int (* pAdd3) (int (* pAdd) (int, int), int, int, int),
                                int, int, int, int),
                int (* pAdd3) ( int (* pAdd) (int, int),
                                int, int, int),
                int (* pAdd) (int, int),
                int, int, int, int, int); 
  //pAdd5 = &add5;
  return 0;
}
